interface Gift {
    id: number;
    name: string;
    rate: number;
    pitch: number;
    accRate: number;
}
interface UserPool {
    [key: string]: User;
}
interface pitchRecord extends Gift {
    /** 剩余保底抽次 */
    calcTime: number;
    /** 完全保底次数 */
    pitchTime: number;
    /** 总共抽中次数 */
    totalTime: number;
}

export class User {
    readonly userID: string;
    readonly wishRecords: Gift[] = [];
    readonly pitchArray: pitchRecord[] = [];

    /** 记录用户的抽卡保底情况  */
    constructor(userID: string, star: Gift[]) {
        this.userID = userID;
        this.pitchArray = star.map((i) => ({
            ...i,
            calcTime: i.pitch,
            pitchTime: 0,
            totalTime: 0,
        }));
    }
    /** 这是系统触发的保底, 重置某个奖品的保底 */
    systemPitch(gift: Gift) {
        this.pitchArray[gift.id - 1].pitchTime++;
        return this.resetPitch(gift);
    }
    /** 重置某个奖品的保底 */
    resetPitch(gift: Gift) {
        return this.pitchArray.some((i) => {
            if (gift.name === i.name) {
                i.calcTime = i.pitch;
                i.totalTime++;
                return true;
            }
        });
    }
    /** 抽中奖品后记录奖品 */
    record(gift: Gift) {
        this.wishRecords.push(gift);
    }
}
interface InputTemplate {
    star: Omit<Gift, "accRate" | "id">[];
    voidGift: Pick<Gift, "name">;
    random?: typeof WishSystem.prototype.random;
}

export class WishSystem {
    /** 奖品设定*/
    private star: Gift[] = [];

    /** 没有中任何奖的兜底奖品。。。 */
    private voidGift: Pick<Gift, "name" | "id">;

    /** 用户数据记录,不允许被查看 */
    private UserPool: UserPool = {};
    /** 无限随机祈愿池 具有保底机制
     * @param star 奖品
     * @param voidGift 谢谢惠顾类的物品
     * @param random 随机算法，可以被自定义
     */
    constructor({ star, voidGift, random }: InputTemplate) {
        // 按贵重程度排序奖品，并确定最大循环点
        let accRate = 0;
        this.star = star
            .sort((a, b) => b.pitch - a.pitch)
            .map((cur, index) => {
                return { ...cur, accRate: accRate + cur.rate, id: index + 1 };
            });
        this.voidGift = { ...voidGift, id: 0 };
        if (random) this.random = random;
    }
    /** 检测一个 User 的保底。。。 */
    private CheckPitch(user: User) {
        // 寻找是否有保底,并且如果同时保底两种，取前面概率较小的一种
        // 这个时候将会进行“推迟保底的操作”
        return user.pitchArray.reduce((pitch, cur, index) => {
            cur.calcTime -= 1;
            if (cur.calcTime <= 0 && pitch === -1) {
                cur.calcTime = cur.pitch;
                return index;
            }
            return pitch;
        }, -1);
    }
    /** 随机算法，可以直接改为自定义; 默认不适用随机种子     */
    public random(userID: string, wishCalc: number) {
        return Math.random();
    }

    private createUser(ID: string = Math.random() + "") {
        this.UserPool[ID] = new User(ID, this.star);
    }

    /** 直接填入你的 ID 号，没有的话系统会自动创建 */
    wish(userID: string) {
        if (!(userID in this.UserPool)) {
            this.createUser(userID);
        }
        const user = this.UserPool[userID];
        const giftIndex = this.CheckPitch(user);
        let gift: Gift;
        if (giftIndex !== -1) {
            // 直接保底了奖品
            gift = this.star[giftIndex];
            user.systemPitch(gift);
        } else {
            const wishCalc = user.wishRecords.length;
            gift = this.normalWish(userID, wishCalc);
            if (gift !== this.voidGift) {
                // 抽中奖品了
                user.resetPitch(gift);
            }
        }
        user.record(gift);
        return gift;
    }
    /** 随机抽取一个物品 */
    private normalWish(userID: string, wishCalc: number) {
        // 奖品数值范围从低到高排列，希望越小星级越高，那么随机数落在哪个区域就可以实现等级划分了
        const hope = this.random(userID, wishCalc);
        let [gift] = this.star.filter((i) => hope <= i.accRate);
        return gift || this.voidGift;
    }
}
